package com.example.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

@Service
@Slf4j
public class AtomicExampleService {

    private final AtomicInteger atomicCounter = new AtomicInteger(0);
    // 使用 AtomicStampedReference 来解决 ABA 问题
    private final AtomicStampedReference<String> atomicStampedRef = new AtomicStampedReference<>("A", 0);

    /**
     * 多线程环境中进行计数器增加操作
     */
    public void incrementInParallel() {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    // incrementAndGet是基于CAS来完成的，而CAS是基于硬件原子指令来完成的，可能会出现ABA问题
                    int newValue = atomicCounter.incrementAndGet();
                    log.info("线程 [{}] 增加计数器: {}", Thread.currentThread().getName(), newValue);
                    try {
                        Thread.sleep(100); // 模拟一些工作
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }).start();
        }
    }

    /**
     * 多线程环境中进行计数器减少操作
     */
    public void decrementInParallel() {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    int newValue = atomicCounter.decrementAndGet();
                    log.info("线程 [{}] 减少计数器: {}", Thread.currentThread().getName(), newValue);
                    try {
                        Thread.sleep(100); // 模拟一些工作
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }).start();
        }
    }

    /**
     * 获取当前计数器的值
     */
    public int getCounterValue() {
        return atomicCounter.get();
    }

    /**
     * 模拟 ABA 问题并解决它
     */
    public void simulateABAProblem() {
        int[] stampHolder = new int[1];
        String initialRef = atomicStampedRef.get(stampHolder);
        int initialStamp = stampHolder[0];

        log.info("初始值: {}, 初始版本号: {}", initialRef, initialStamp);

        // 模拟 ABA 问题
        atomicStampedRef.compareAndSet("A", "B", initialStamp, initialStamp + 1); // 改为 B，版本号 +1
        log.info("更新值到 B，版本号更新到: {}", atomicStampedRef.getStamp());

        atomicStampedRef.compareAndSet("B", "A", atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1); // 改回 A，版本号 +1
        log.info("更新值回 A，版本号更新到: {}", atomicStampedRef.getStamp());

        // 尝试使用最初的版本号进行 CAS 操作
        boolean success = atomicStampedRef.compareAndSet("A", "C", initialStamp, initialStamp + 1);
        log.info("CAS 操作是否成功: {}", success);
        log.info("当前值: {}, 当前版本号: {}", atomicStampedRef.getReference(), atomicStampedRef.getStamp());
    }
}
